package com.ruoyi.bpm.service.task.impl;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.ruoyi.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageReqVO;
import com.ruoyi.bpm.domain.task.BpmProcessInstanceCopy;
import com.ruoyi.bpm.enums.ErrorCodeConstants;
import com.ruoyi.bpm.mapper.task.BpmProcessInstanceCopyMapper;
import com.ruoyi.bpm.service.definition.BpmProcessDefinitionService;
import com.ruoyi.bpm.service.task.BpmProcessInstanceCopyService;
import com.ruoyi.bpm.service.task.BpmProcessInstanceService;
import com.ruoyi.bpm.service.task.BpmTaskService;
import com.ruoyi.common.orm.core.page.PageQuery;
import com.ruoyi.common.orm.core.page.TableDataInfo;
import com.ruoyi.common.orm.core.service.impl.BaseServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.util.Collection;
import java.util.List;

import static com.ruoyi.bpm.domain.task.table.BpmProcessInstanceCopyTableDef.BPM_PROCESS_INSTANCE_COPY;
import static com.ruoyi.common.core.utils.ServiceExceptionUtil.exception;
import static com.ruoyi.common.core.utils.CollectionUtils.convertList;

/**
 * 流程抄送 Service 实现类
 *
 * @author kyle
 */
@Service
@Validated
@Slf4j
public class BpmProcessInstanceCopyServiceImpl extends BaseServiceImpl<BpmProcessInstanceCopyMapper, BpmProcessInstanceCopy> implements BpmProcessInstanceCopyService {

    @Resource
    @Lazy // 延迟加载，避免循环依赖
    private BpmTaskService taskService;

    @Resource
    @Lazy // 延迟加载，避免循环依赖
    private BpmProcessInstanceService processInstanceService;
    @Resource
    @Lazy // 延迟加载，避免循环依赖
    private BpmProcessDefinitionService processDefinitionService;

    @Override
    public QueryWrapper query() {
        return super.query().from(BPM_PROCESS_INSTANCE_COPY);
    }

    @Override
    public void createProcessInstanceCopy(Collection<Long> userIds, String taskId) {
        // 1.1 校验任务存在
        Task task = taskService.getTask(taskId);
        if (ObjectUtil.isNull(task)) {
            throw exception(ErrorCodeConstants.TASK_NOT_EXISTS);
        }
        // 1.2 校验流程实例存在
        String processInstanceId = task.getProcessInstanceId();
        ProcessInstance processInstance = processInstanceService.getProcessInstance(processInstanceId);
        if (processInstance == null) {
            throw exception(ErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS);
        }
        // 1.3 校验流程定义存在
        ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition(
            processInstance.getProcessDefinitionId());
        if (processDefinition == null) {
            throw exception(ErrorCodeConstants.PROCESS_DEFINITION_NOT_EXISTS);
        }

        // 2. 创建抄送流程
        List<BpmProcessInstanceCopy> copyList = convertList(userIds, userId -> new BpmProcessInstanceCopy()
            .setUserId(userId).setStartUserId(Long.valueOf(processInstance.getStartUserId()))
            .setProcessInstanceId(processInstanceId).setProcessInstanceName(processInstance.getName())
            .setCategory(processDefinition.getCategory()).setTaskId(taskId).setTaskName(task.getName()));
        mapper.insertBatch(copyList);
    }

    @Override
    public TableDataInfo<BpmProcessInstanceCopy> getProcessInstanceCopyPage(Long userId,
                                                                            BpmProcessInstanceCopyPageReqVO pageReqVO) {
        QueryWrapper queryWrapper = query()
            .where(BPM_PROCESS_INSTANCE_COPY.USER_ID.eq(userId, userId != null))
            .and(BPM_PROCESS_INSTANCE_COPY.PROCESS_INSTANCE_NAME.like(pageReqVO.getProcessInstanceName(), StrUtil.isNotBlank(pageReqVO.getProcessInstanceName())))
            .and(BPM_PROCESS_INSTANCE_COPY.CREATE_TIME.between(pageReqVO.getCreateTime(), ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())))
            .orderBy(BPM_PROCESS_INSTANCE_COPY.ID.desc());
        Page<BpmProcessInstanceCopy> page = this.pageAs(PageQuery.build(), queryWrapper, BpmProcessInstanceCopy.class);
        return TableDataInfo.build(page);
    }

}
